package com.tender.utils.cryptography;

import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;

/**
 * 采用 RSA（非对称） + AES（对称） 混合加密、解密方式，来保证前后端的数据安全
 */
@SuppressWarnings("all")
public class AESUtil {

    private static final Logger logger = LoggerFactory.getLogger(AESUtil.class);

    public final static String AES_ALGORITHMS = "AES";

    /**
     * 其中CBC是加密模式，PKCS5Padding 是填充模式，用于确保明文长度满足AES块大小的要求。
     */
    public final static String AES_PATTERN_ALGORITHMS = "AES/CBC/PKCS5Padding";

    public final static int AES_KEY_SIZE = 128;

    public final static String DEFAULT_ENCODING = "UTF-8";

    private static final Base64.Encoder base64Encoder = Base64.getEncoder();
    private static final Base64.Decoder base64Decoder = Base64.getDecoder();

    private static final String DEFAULT_AES_KEY = "3b99+zSZRLesNjaxpD6PtQ==";

    private static final String DEFAULT_IV = "bnLomKySahg67romRuP5gQ==";

    /**
     * 生成AES密钥，base64编码格式 (128位)
     *
     * @return
     * @throws Exception
     */
    public static String getKeyAES_128() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance(AES_ALGORITHMS);
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(UUID.randomUUID().toString().getBytes());
        keyGen.init(AES_KEY_SIZE, random);
        SecretKey key = keyGen.generateKey();
        String base64str = base64Encoder.encodeToString(key.getEncoded());
        return base64str;
    }

    public static byte[] generateIV() throws Exception {
        byte[] iv = new byte[16]; // IV is always 16 bytes for AES
        // SecureRandom random = new SecureRandom();
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(UUID.randomUUID().toString().getBytes());
        random.nextBytes(iv);
        return iv;
    }

    /**
     * 生成AES密钥，base64编码格式 (256位)
     *
     * @return
     * @throws Exception
     */
//    public static String getKeyAES_256() throws Exception {
//        // 256需要换jar包暂时用128
//        String base64str = getKeyAES_128();
//        return base64str;
//    }

    /**
     * 根据base64Key获取SecretKey对象
     *
     * @param base64Key
     * @return
     */
    public static SecretKey loadKeyAES(String base64Key) {
        byte[] bytes = base64Decoder.decode(base64Key);
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, AES_ALGORITHMS);
        return secretKeySpec;
    }

    /**
     * AES 加密字符串，SecretKey对象
     *
     * @param key         SecretKey 对象
     * @param encryptData 要加密的字符串
     * @param encode      编码类型
     * @return
     */
    public static String encrypt(SecretKey key, String encryptData, byte[] iv, String encode) {
        try {
            final Cipher cipher = Cipher.getInstance(AES_PATTERN_ALGORITHMS);
            if (null != iv) {
                cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
            } else {
                cipher.init(Cipher.ENCRYPT_MODE, key);
            }
            byte[] encryptBytes = encryptData.getBytes(encode);
            byte[] result = cipher.doFinal(encryptBytes);
            return base64Encoder.encodeToString(result);
        } catch (Exception e) {
            logger.error("AES加密异常:" + e.getMessage());
        }
        return null;
    }

    /**
     * AES 加密字符串，base64Key对象
     *
     * @param base64Key
     * @param encryptData
     * @param encode
     * @return
     */
    public static String encrypt(String base64Key, String encryptData, byte[] iv, String encode) {
        SecretKey key = loadKeyAES(base64Key);
        return encrypt(key, encryptData, iv, encode);
    }

    public static String encrypt(String base64Key, String encryptData, byte[] iv) {
        SecretKey key = loadKeyAES(base64Key);
        return encrypt(key, encryptData, iv, DEFAULT_ENCODING);
    }

    public static String encrypt(SecretKey key, String encryptData, byte[] iv) {
        return encrypt(key, encryptData, iv, DEFAULT_ENCODING);
    }

    public static String encrypt(SecretKey key, String encryptData) {
        return encrypt(key, encryptData, null, DEFAULT_ENCODING);
    }

    public static String encrypt(String base64Key, String encryptData) {
        return encrypt(base64Key, encryptData, null, DEFAULT_ENCODING);
    }

    public static String encrypt(String encryptData) {
        return encrypt(DEFAULT_AES_KEY, encryptData, base64Decoder.decode(DEFAULT_IV), DEFAULT_ENCODING);
    }

    /**
     * AES 解密字符串，SecretKey对象
     *
     * @param key         SecretKey 对象
     * @param decryptData 需要解密的字符串
     * @param encode      字符编码
     * @return
     */
    public static String decrypt(SecretKey key, String decryptData, byte[] iv, String encode) {
        try {
            final Cipher cipher = Cipher.getInstance(AES_PATTERN_ALGORITHMS);
            if (null != iv) {
                cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
            } else {
                cipher.init(Cipher.DECRYPT_MODE, key);
            }

            byte[] decryptBytes = base64Decoder.decode(decryptData);
            byte[] result = cipher.doFinal(decryptBytes);
            return new String(result, encode);
        } catch (Exception e) {
            logger.error("AES解密异常:" + e.getMessage());
        }
        return null;
    }

    public static String decrypt(String base64Key, String decryptData, byte[] iv, String encode) {
        SecretKey key = loadKeyAES(base64Key);
        return decrypt(key, decryptData, iv, encode);
    }

    public static String decrypt(SecretKey key, String decryptData, byte[] iv) {
        return decrypt(key, decryptData, iv, DEFAULT_ENCODING);
    }

    public static String decrypt(String base64Key, String decryptData, byte[] iv) {
        return decrypt(base64Key, decryptData, iv, DEFAULT_ENCODING);
    }

    public static String decrypt(SecretKey key, String decryptData) {
        return decrypt(key, decryptData, null, DEFAULT_ENCODING);
    }

    public static String decrypt(String base64Key, String decryptData) {
        return decrypt(base64Key, decryptData, null, DEFAULT_ENCODING);
    }

    public static String decrypt(String decryptData) {
        return decrypt(DEFAULT_AES_KEY, decryptData, base64Decoder.decode(DEFAULT_IV), DEFAULT_ENCODING);
    }

    public static void main(String[] args) throws Exception {
        String keyAES128 = getKeyAES_128();
        System.out.println("========= keyAES128 ==============" + keyAES128);

        SecretKey secretKey = loadKeyAES(keyAES128);
        // System.out.println("========= secretKey ==============" + secretKey);
        byte[] iv = generateIV();
        System.out.println("========= iv ==============" + iv);

        String text = "123456789";

        String str = base64Encoder.encodeToString(iv);
        System.out.println(" =========== iv base64 后 ======== " + str);
        byte[] decode = base64Decoder.decode(str);
        System.out.println(" =========== iv base64 解码后 ======== " + decode);

        String encrypt = encrypt(secretKey, text, decode);
        System.out.println("========= 原文 ==============" + text);
        System.out.println("========= 加密后 ==============" + encrypt);
        String decrypt = decrypt(secretKey, encrypt, decode);
        System.out.println("========= 解密后 ==============" + decrypt);

        System.out.println("******************************************************");
        System.out.println("========= 测试 默认 secretKey 的加密和解密 ==============");
        System.out.println("******************************************************");

        System.out.println("========= 原始内容 ========= " + "123456");
        String encrypt1 = encrypt("123456");

        System.out.println("========= 默认加密后 ========= " + encrypt1);
        String decrypt1 = decrypt(encrypt1);
        System.out.println("========= 默认解密后 ========= " + decrypt1);
        System.out.println();
        System.out.println("******************************************************");
        System.out.println("========= 后端测试前端传递的内容 ==============");
        System.out.println("******************************************************");


        String secretAES = "UKyfNIGiRT19s0kPx3V2Jg==";

        String data = "GGoAFRaisR+TlJMoP7KIovzj+27URLCX+OkevMuEPBJoiorJZVK23xjvFyrZFJXCr+3Z9n++hD9lKtBkOaNHglrWRXslByI2OuReYNqvFIy/OJocJ8Bgx9IjHnqbh36K8HNW29PYK9267PnNxRQiTgfM778FotH/NvpvxhRMHJCnzAn2QMqutwFanwds8DSclr8yloHhl5hHUIolT/enn8i1/WQO1ZGJJXC2aN2f2V8NFfvRoxnFt47kV7LopFf/wznXukLyymJKbw/bVy34zW1KSmhSfZxSbMZS2jnhlukT5fiIrgC+PrV7jEDgRyAqLNLlI5bY/iJu/d+gf4npdw==";

        String ivAES = "nYRxvBJNBh30J5NDEneHTg==";

        String decrypt2 = decrypt(secretAES, data, base64Decoder.decode(ivAES));
        System.out.println(decrypt2);
    }

}
